# -*- coding: utf-8 -*-

import os,math

import Image,ImageColor,ImageDraw,ImageWin,ImageFont
    
class ChartItem():
    
    def __init__(self,label,desc,data,start,sweep,color):
        self.label = label
        self.desc = desc
        self.data = data
        self.start = start
        self.sweep = sweep
        self.color = color
    
    def __str__(self):
        return "%s,%s,%f,%f,%f,%s" % \
                (self.label,self.desc,self.data,self.start,self.sweep, self.color)
    
    def __unicode__(self):
        return u"%s,%s,%f,%f,%f,%s" % \
                (self.label,self.desc,self.data,self.start,self.sweep, self.color)
        
class Chart():
    def __init__(self):
        self.DataPoints = []
        self.colorlist = [
            "chocolate",
            "yellowgreen",
            "olive",
            "darkkhaki",
            "sienna",
            "palegoldenrod",
            "peru",
            "tan",
            "khaki",
            "darkgoldenrod",
            "maroon",
            "olivedrab",
            ]
    
    def SetColor(self,index,newcolor):
        if newcolor in ImageColor.colormap.keys():
            self.colorlist[index] = newcolor
        else:
            raise ValueError("unknown color specifier: %s" % newcolor)
    
    def GetColor(self,index):
        return self.colorlist[index%len(self.colorlist)]

def makeShortLabel(text):
    if len(text) > 2:
        return text[0]+text[-1]+str(len(text))
    return text
        
class BarChart(Chart):   
    def __init__(self):
        Chart.__init__(self)
        self._totalWidth = 640.0
        self._totalHeight = 480.0

        self._backColor = "white"
        self._fontColor = "black"
        self._lineColor = "#CCCCCC"
        
        self._topBuffer = 30
        self._bottomBuffer = 30
        self._rightBuffer = 30
        
        #self._font = ImageFont.load_default()
        self._font = ImageFont.truetype("simhei.ttf", 12)
        #self._displayLegend = False
        #self._displayBarData = False
        
        self._yTickCount = 5;
        self._yTickValue = 0;
        
        self._maxValue = 0
        
        self.Point0 = (0,0)
        
        self._scaleFactor = self._maxValue / self._totalHeight
    
    def SetData(self, xValues, yValues):     
        if len(xValues) != len(yValues):
            raise ValueError('X data count is different from Y data count')
        
        self.DataPoints = []
        self._maxValue = 0
        
        for i in range(len(xValues)):
            label = xValues[i]
            data = yValues[i]
            shortlbl = makeShortLabel(label)
            item = ChartItem(shortlbl, label, data, 0.0, 0.0, self.GetColor(i))
            self.DataPoints.append(item)
            if self._maxValue < data:
                self._maxValue = data
        self.CalculateTickAndMax()
    
    def CalculateTickAndMax(self):
        tempMax = 0.0
        self._maxValue *= 1.1
        if self._maxValue == 0:
            tempMax = 1
        else:
            exp = math.floor(math.log10(self._maxValue)) - 20
            tempMax = int(math.ceil(self._maxValue/math.pow(10, exp)) * math.pow(10,exp))
        self._yTickValue = tempMax / self._yTickCount
        expTick = float(math.floor(math.log10(self._yTickValue)))
        self._yTickValue = int(math.ceil(self._yTickValue / math.pow(10, expTick)) \
                                * math.pow(10, expTick))
        
        self._maxValue = self._yTickValue * self._yTickCount
        
        self._scaleFactor = self._maxValue / (self._totalHeight-self._topBuffer-self._bottomBuffer)
    
    def Draw(self):
                
        for p in self.DataPoints:
            print unicode(p)
        print self._maxValue
        print self._yTickCount
        print self._yTickValue
        
        height = int(self._totalHeight)
        width = int(self._totalWidth)
        
        img = Image.new('RGB',(width,height),self._backColor)
        draw = ImageDraw.Draw(im = img)
        draw.rectangle((0,0,width,height),fill = self._backColor)
               
        self.DrawVerticalLabelArea(draw)
        self.DrawBars(draw)
        self.DrawXLabelArea(draw)
        del draw
        return img  
    
    def DrawBars(self, draw):      
        count = len(self.DataPoints)
        xlength = (self._totalWidth - self._rightBuffer - self.Point0[0]) 
        itemWidth = xlength/count
        barWidth = itemWidth /2
        
        for i in range(count):
            item = self.DataPoints[i]
            print unicode(item)
            textsize = self._font.getsize("%.2f"%(item.data))
            
            start = (self.Point0[0]+ i * itemWidth + (itemWidth - barWidth)/2,\
                     self.Point0[1] - item.data/self._scaleFactor)
            end =(start[0]+barWidth, self.Point0[1])
            draw.rectangle((start,end),fill = item.color)
            
            start = (start[0]+barWidth/2 - textsize[0]/2, start[1]-textsize[1])
            draw.text(start,"%.2f"%(item.data),fill=self._fontColor,font=self._font)
    
    def DrawXLabelArea(self, draw):
        end = (self._totalWidth,self.Point0[1])
        draw.line((self.Point0,end),\
                  fill=self._lineColor, width = 1)
        
        count = len(self.DataPoints)
        xlength = (self._totalWidth - self._rightBuffer - self.Point0[0]) 
        itemWidth = xlength/count
        
        for i in range(count):
            item = self.DataPoints[i]
            textsize = self._font.getsize(item.desc)
            start = (self.Point0[0]+i*itemWidth+itemWidth/2 - textsize[0]/2,self.Point0[1]+4)
            draw.text(start,item.desc,fill=self._fontColor,font=self._font)
    
    def DrawVerticalLabelArea(self, draw):
        ticksize = self._font.getsize("%d"%(self._maxValue))       
        tickX = ticksize[0] + 8
        tickLen = 4
        
        for i in range(self._yTickCount):
            curY = self._topBuffer + i* self._yTickValue/ self._scaleFactor
            labelY = curY - ticksize[1]/2
            print curY,labelY
            currentTick = "%d"%(self._maxValue - i*self._yTickValue)
            draw.text((5,labelY),currentTick,fill=self._fontColor,font=self._font)
            draw.line((tickX,curY,tickX+tickLen,curY), fill = "black", width=1)
        
        start = (tickX + tickLen,self._topBuffer)
        end = (tickX + tickLen, self._topBuffer + self._yTickCount * self._yTickValue/ self._scaleFactor)
        self.Point0 = end
        draw.line((start,end), fill=self._lineColor, width = 1)
            
    def DrawLegend(self, draw):
        pass
    
if "__main__" == __name__:
    pass
    DIR_PATH = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
    mychart = BarChart()
    mychart.SetData((u"CC",u"妮子",u"大师兄",u"joe",u"joe哥",),\
                     (1296.2,435.4,118,496.1,1937.1,))
    img = mychart.Draw()
    img.save("mychart.png","png")


